package com.photoeditor.demo.model.image.collage.templet;

import com.photoeditor.demo.model.image.collage.templet.attr.AttrFactory;
import com.photoeditor.demo.model.image.collage.templet.attr.IStatus;

import java.util.ArrayList;
import java.util.List;

/**
 * 模板的基础类
 * 一个拼接模板
 */
public class CollageTemplet {

    public static final int TYPE_POINT = 1;
    public static final int TYPE_SVG = 2;

    private int mType;

    private int mCollageNumber;
    // 是否禁止拖动
    private boolean mForbidDrag;

    private ArrayList<CollagePoints> mCollagePoints;

    //预处理属性和CollagePoints一一对应
    private ArrayList<IStatus> mPreStatus;

    public CollageTemplet(int type){
        mType = type;
        mCollagePoints = new ArrayList<CollagePoints>();
        mPreStatus = new ArrayList<IStatus>();
        mCollageNumber = 0;
    }

    public CollagePoints getCollagePoints(int i){
        if(i < mCollageNumber) {
            return mCollagePoints.get(i);
        }
        return null;
    }

    public void setForbidDrag(boolean forbidDrag) {
        mForbidDrag = forbidDrag;
    }

    public boolean isForbidDrag() {
        return mForbidDrag;
    }

    public IStatus getPreStatus(int i){
        if(i < mCollageNumber) {
            return mPreStatus.get(i);
        }
        return null;
    }

    public void addCollage(CollagePoints collagePoints){
        mCollagePoints.add(collagePoints);
        mPreStatus.add(AttrFactory.createDefaultAttr());
        mCollageNumber = mCollagePoints.size();
    }

    public void addCollage(CollagePoints collagePoints, IStatus status){
        mCollagePoints.add(collagePoints);
        mPreStatus.add(status);
        mCollageNumber = mCollagePoints.size();
    }

    public int getType(){
        return mType;
    }

    public boolean isType(int type){
        return (mType == type);
    }

    public int getCollageNumber(){
        return mCollageNumber;
    }

    /**
     * 获取可拖拽调整区域大小的点
     * 判断该边可拖拽的方法：该边有与之重合的边且连接该边两端所在的两条直线与对应的重合的边的两端所在的两条直线斜率相等
     * 拖拽点的位置是边的中点
     * @param currentCollagePoints 当前选中的区域
     * @param trueWidth
     * @param trueHeight
     * @param distanceProgress 边距
     * @return
     */
    public List<DragPoint> getDragPointList(CollagePoints currentCollagePoints, float trueWidth,
                                        float trueHeight, int distanceProgress) {
        List<DragPoint> dragPointList = new ArrayList<>();
        if (isForbidDrag() || currentCollagePoints == null) {
            return dragPointList;
        }
        int currentIndex = -1;
        for (int i = 0; i < mCollageNumber; i++) {
            if (currentCollagePoints.equals(getCollagePoints(i))) {
                currentIndex = i;
                break;
            }
        }
        if (currentIndex == -1) {
            return dragPointList;
        }

        // 查找重合的边
        for (int i = 0; i < mCollageNumber; i++) {
            if (i == currentIndex) {
                continue;
            }
            CollagePoints collagePoints = getCollagePoints(i);
            int pointNumber = collagePoints.getLength();
            for (int j = 0; j < pointNumber; j++) {
                int headPointIndex = j;
                int tailPointIndex = j + 1;
                if (tailPointIndex >= pointNumber) {
                    tailPointIndex = 0;
                }
                int headPointIndexBefore = j - 1;
                int tailPointIndexAfter = tailPointIndex + 1;
                if (headPointIndexBefore < 0) {
                    headPointIndexBefore = pointNumber - 1;
                }
                if (tailPointIndexAfter >= pointNumber) {
                    tailPointIndexAfter = 0;
                }

                Point headPoint = collagePoints.getPoint(headPointIndex);
                Point tailPoint = collagePoints.getPoint(tailPointIndex);
                Point headPointBefore = collagePoints.getPoint(headPointIndexBefore);
                Point tailPointAfter = collagePoints.getPoint(tailPointIndexAfter);


                // 排除垂直贴边、水平贴边
                boolean isVerticalSide = headPoint.x == tailPoint.x && (tailPoint.x == 0 || tailPoint.x == 1);
                boolean isHorizontalSide = headPoint.y == tailPoint.y && (tailPoint.y == 0 || tailPoint.y == 1);
                if (!isVerticalSide && !isHorizontalSide) {
                    int currentPointNumber = currentCollagePoints.getLength();
                    for (int m = 0; m < currentPointNumber; m++) {
                        int currentHeadPointIndex = m;
                        int currentTailPointIndex = m + 1;
                        if (currentTailPointIndex >= currentPointNumber) {
                            currentTailPointIndex = 0;
                        }
                        int currentHeadPointIndexBefore = m - 1;
                        int currentTailPointIndexAfter = currentTailPointIndex + 1;
                        if (currentHeadPointIndexBefore < 0) {
                            currentHeadPointIndexBefore = currentPointNumber - 1;
                        }
                        if (currentTailPointIndexAfter >= currentPointNumber) {
                            currentTailPointIndexAfter = 0;
                        }
                        Point currentHeadPoint = currentCollagePoints.getPoint(currentHeadPointIndex);
                        Point currentTailPoint = currentCollagePoints.getPoint(currentTailPointIndex);
                        Point currentHeadPointBefore = currentCollagePoints.getPoint(currentHeadPointIndexBefore);
                        Point currentTailPointAfter = currentCollagePoints.getPoint(currentTailPointIndexAfter);
                        boolean match = false;
                        // 匹配共边
                        if (headPoint.approximationEquals(currentHeadPoint)) {
                            // 正序共边
                            if (isSameSlop(new Line(headPoint, tailPoint, headPointBefore, tailPointAfter),
                                    new Line(currentHeadPoint, currentTailPoint, currentHeadPointBefore, currentTailPointAfter))) {
                                match = true;
                            }
                        } else if (tailPoint.approximationEquals(currentHeadPoint)) {
                            // 逆序共边
                            if (isSameSlop(new Line(tailPoint, headPoint, tailPointAfter, headPointBefore),
                                    new Line(currentHeadPoint, currentTailPoint, currentHeadPointBefore, currentTailPointAfter))) {
                                match = true;
                            }
                        }
                        if (match) {
                            Point trueHeadPoint = currentCollagePoints.getCurrentPoint(
                                    currentHeadPointIndex, trueWidth, trueHeight, distanceProgress);
                            Point trueTailPoint = currentCollagePoints.getCurrentPoint(
                                    currentTailPointIndex, trueWidth, trueHeight, distanceProgress);
                            DragPoint.Orientation orientation;
                            if (trueHeadPoint.x == trueTailPoint.x) {
                                orientation = DragPoint.Orientation.horizontal;
                            } else if (trueHeadPoint.y == trueTailPoint.y) {
                                orientation = DragPoint.Orientation.vertical;
                            } else {
                                float slop = (trueHeadPoint.y - trueTailPoint.y) / (trueHeadPoint.x - trueTailPoint.x);
                                if (slop > 1 || slop < -1) {
                                    orientation = DragPoint.Orientation.horizontal;
                                } else {
                                    orientation = DragPoint.Orientation.vertical;
                                }
                            }
                            dragPointList.add(new DragPoint((trueHeadPoint.x + trueTailPoint.x) / 2,
                                    (trueHeadPoint.y + trueTailPoint.y) / 2, orientation));
                        }
                    }
                }
            }
        }

        return dragPointList;

    }

    /**
     * 两个线段是否有相同的斜率
     * @param one
     * @param two
     * @return
     */
    private boolean isSameSlop(Line one, Line two) {
        if (one.headPointBefore.x == one.headPoint.x || two.headPointBefore.x == two.headPoint.x) {
            return one.headPointBefore.x == one.headPoint.x && two.headPointBefore.x == two.headPoint.x;
        } else if (one.headPointBefore.y == one.headPoint.y || two.headPointBefore.y == two.headPoint.y) {
            return one.headPointBefore.y == one.headPoint.y && two.headPointBefore.y == two.headPoint.y;
        } else {
            float slopOne = (one.headPointBefore.y - one.headPoint.y) / (one.headPointBefore.x - one.headPoint.x);
            float slopTwo = (two.headPointBefore.y - two.headPoint.y) / (two.headPointBefore.x - two.headPoint.x);
            return Math.abs(slopOne - slopTwo) < CollagePoints.ADMISSIBLE_ERROR;
        }
    }


    /**
     * 定义用于匹配的线段
     */
    private class Line {
        Point headPoint;
        Point tailPoint;
        Point headPointBefore;
        Point tailPointAfter;

        /**
         *
         *        headPoint 1-----1  tailPoint
         *                  1     1
         * headPointBefore  1     1  tailPointAfter
         * @param headPoint
         * @param tailPoint
         * @param headPointBefore
         * @param tailPointAfter
         */
        public Line(Point headPoint, Point tailPoint, Point headPointBefore, Point tailPointAfter) {
            this.headPoint = headPoint;
            this.tailPoint = tailPoint;
            this.headPointBefore = headPointBefore;
            this.tailPointAfter = tailPointAfter;
        }
    }

    @Override
    public CollageTemplet clone() {
        CollageTemplet collageTemplet = new CollageTemplet(mType);
        if (mCollagePoints != null) {
            for (int i = 0; i < mCollagePoints.size(); ++i) {
                CollagePoints collagePoints = mCollagePoints.get(i);
                collageTemplet.addCollage(collagePoints.clone(), getPreStatus(i));
            }
        }
        collageTemplet.setForbidDrag(mForbidDrag);
        return collageTemplet;
    }

}
